/* 
 * File:   main.cpp
 * Author: fliaali
 *
 * Created on 20 de septiembre de 2013, 14:42
 */

#include <cstdlib>
#include <string.h>
#include <stdio.h>
#include <fstream>
#include <iostream>
#include <sstream>


#include "Utils/Directory.h"
#include "Utils/Parser.h"
#include "Utils/ClusteringKMeans.h"


#define MAX_COMANDO 4
const char* EXTENSION = ".txt";
const char* RUTA_HASHMINS_LEER = "/home/fliaali/Repositorio Datos/svn/Src/TpDatos/HashMins";
const char* RUTA_HASHMINS = "/home/fliaali/Repositorio Datos/svn/Src/TpDatos/HashMins/";
const char* PREFIJO_HASHMIN = "/home/fliaali/Repositorio Datos/svn/Src/TpDatos/HashMins/hashmin_";
const char* RUTA_CLUSTERS = "/home/fliaali/Repositorio Datos/svn/Src/TpDatos/Clusters";
const char* RUTA_CLUSTER_CREAR = "/home/fliaali/Repositorio Datos/svn/Src/TpDatos/Clusters/";
const char* PREFIJO_CLUSTER = "/home/fliaali/Repositorio Datos/svn/Src/TpDatos/Clusters/cluster_";
const char* ARCH_CENTROIDES = "/home/fliaali/Repositorio Datos/svn/Src/TpDatos/centroides.txt";
const char* ARCH_LISTADO = "/home/fliaali/Repositorio Datos/svn/Src/TpDatos/listado.txt";
const int MAX_IT_KMEANS = 50;

using namespace std;

typedef enum{CLUSTERING,LISTAR_LIBROS,LISTAR_GRUPOS,AGREGAR_LIBRO}t_opcion;

t_opcion veo_comando_general(int argc, char** argv, char** comandos){
    int i;
    if (argc == 1) return (t_opcion) -1;
    for(i=0; i<MAX_COMANDO; i++){
        if(strcmp(comandos[i],argv[1]) == 0) return (t_opcion)i;
    }
    return (t_opcion) -1;
}

int Busco_Barra(const char* archivo){
    int pos = 0;
    for(int k = 0;k<strlen(archivo);k++){
        if(archivo[k]=='/') pos = k+1;
    }
    return pos;
}

void Clear(char* s){
    for(int i=0;i<strlen(s);i++){
        s[i]='\0';
    }
}

void f_clustering(int argc, char** argv){
 
    Log* lg = Log::getInstance();
    char* doc_varios_cluster;
    bool varios_cluster = false;
    string ruta_libros;
    int clusters = -1;
     if((argc != 5) && (argc != 7)){
        printf("Comando Invalido\n");
        return;
    }
   
    ruta_libros= argv[2];
    if(argc == 5){
        doc_varios_cluster = argv[4];
    }
    else{
        clusters = atoi(argv[4]);
        doc_varios_cluster = argv[6];
    }
    if(strcmp(doc_varios_cluster,"Y") == 0) varios_cluster = true;
     
    string str = ruta_libros;
    std::vector<std::string> files;
    if(!Directory::Existe(ruta_libros)){
        printf("No se encontraron archivos en el directorio");
        return;
    }
    Directory::GetListPath(str, files, EXTENSION);
    if (files.empty()) 
        printf("No se encontraron archivos en el directorio");
    else{
        string stt = RUTA_HASHMINS;
        if(Directory::Existe(stt))
                Directory::Remover(stt);
        else
                Directory::Create(stt);
        int pos,k,largo,copia;
        char nombre[200];
        Clear(nombre);
        Parser* mi_parser = new Parser();
        int archivos_total = files.size();
        
        printf("Inicia Obtener_Vector_HashMin %s \n", lg->getDateTimeNow().c_str());
        for(int i=0;i<archivos_total;i++){
                const char* archivo = files[i].c_str();
                //Generar Archivo Docs (Iddoc=i; Cat(0);Name:files(i)))
                pos = Busco_Barra(archivo);
                Clear(nombre);
                
                strcpy(nombre,PREFIJO_HASHMIN);
                largo = strlen(archivo);
                copia = largo-pos;
                strncpy(nombre+strlen(PREFIJO_HASHMIN),archivo+pos,copia);
                nombre[copia+strlen(PREFIJO_HASHMIN)] ='\0';
                mi_parser->Obtener_Vector_HashMin(archivo,nombre); 
        }
        printf("Fin Obtener_Vector_HashMin %s \n", lg->getDateTimeNow().c_str());
                   
         
      
        if(clusters==-1) 
            clusters = ceil(sqrt(archivos_total/2)); //regla del ORO
        // LLamar a kmeans con los parametros.
        mi_parser->Destruir();
        
        printf("Inicia Cluster %s \n", lg->getDateTimeNow().c_str());
        vector<string> files;
        string str = RUTA_HASHMINS_LEER;
        Directory::GetListPath(str, files, EXTENSION);
        ClusteringKMeans clustr(files, clusters, files.size(), DEF_NUM_MINHASH, MAX_IT_KMEANS);
        int **cl = clustr.Cluster(varios_cluster);
        clustr.SaveFiles(cl,RUTA_CLUSTER_CREAR,PREFIJO_CLUSTER,ARCH_CENTROIDES,ARCH_LISTADO);
        printf("Fin Cluster %s \n", lg->getDateTimeNow().c_str());
       
        
    }
     
    return;
}

void f_listar_libros(int argc, char** argv){
    if(argc != 2){
        printf("Comando Invalido\n");
        return;
    }
    printf("Ok Listar_Libros\n");
    FILE* listado = fopen(ARCH_LISTADO,"r");
    if(listado == NULL){
        printf("No existen archivos,realizar clustering");
        return;
    }
    char letra; 
    char nombre[200];
    Clear(nombre);
    while(!feof(listado)){
        letra=fgetc(listado);
        if(letra == '\n'){
                printf("%s \n",nombre); 
                Clear(nombre);
        }
        else{
                nombre[strlen(nombre)+1] = '\0';
                nombre[strlen(nombre)] = letra;
        }     
    }
    fclose(listado);
    return;
}

void f_listar_grupos(int argc, char** argv){
     if(argc != 2){
        printf("Comando Invalido\n");
        return;
    }
    printf("Ok Listar_Grupos\n");
    string str = RUTA_CLUSTERS; // Ruta donde van a estar los clusters alamcenados
    
    std::vector<std::string> files;
    if(!Directory::Existe(str)){
        printf("No se encontraron archivos en el directorio");
        return;
    }
    Directory::GetListPath(str, files, EXTENSION);
    if (files.empty()) printf("No se encontraron archivos , relizar clustering");
    else{
        int clusters = files.size();
        FILE* cluster_actual;
        const char* archivo;
        char letra;
        char nombre[200];
        Clear(nombre);
        for(int i=0;i<clusters;i++){
            Clear(nombre);
            archivo = files[i].c_str(); 
            printf("\n CLUSTER %c \n",archivo[strlen(PREFIJO_CLUSTER)]);
            cluster_actual = fopen(archivo,"r");
            while(!feof(cluster_actual)){
                letra=fgetc(cluster_actual);
                if(letra == '\n'){
                    printf("%s \n",nombre); 
                    Clear(nombre);
                }
                else{
                    nombre[strlen(nombre)+1] = '\0';
                    nombre[strlen(nombre)] = letra;
                }     
            }
            fclose(cluster_actual);
        }
    }
    return;
}

void f_agregar_libro(int argc, char** argv){
     if(argc != 3){
        printf("Comando Invalido\n");
        return;
    }
    printf("Ok Agregar_Libro\n");
    char* ruta_libro = argv[2];
    //Generar Archivo Docs (Iddoc=i; Cat(0);Name:files(i)))
    int pos = 0;
    for(int k = 0;k<strlen(ruta_libro);k++){
        if(ruta_libro[k]=='/') pos = k+1;
    }
    char nombre_libro[200];
    char hashmin_nuevo[200];
    strncpy(hashmin_nuevo,PREFIJO_HASHMIN,strlen(PREFIJO_HASHMIN));
    int largo = strlen(ruta_libro);  
    strncpy(nombre_libro,ruta_libro+pos,largo-pos);
    nombre_libro[largo-pos]='\0';
    strncpy(hashmin_nuevo+strlen(PREFIJO_HASHMIN),ruta_libro+pos,largo-pos);
    hashmin_nuevo[strlen(PREFIJO_HASHMIN)+largo-pos] = '\0';
    Parser* mi_parser = new Parser();
    mi_parser->Obtener_Vector_HashMin(ruta_libro,hashmin_nuevo);
    mi_parser->Destruir();
    HashSet* hashset_archivo_nuevo = new HashSet();
    hashset_archivo_nuevo->Load(hashmin_nuevo);
    /*en el archivo donde se guardan los centroides (centroides.txt) necito que se
     guarden las rutas de los hashmin de cada uno de ellos. (es con lo que trabaja kmeans?)
     uno por linea*/
    FILE* centroides = fopen(ARCH_CENTROIDES,"r");
    HashSet* hashset_centroide = new HashSet();
    Jaccard* mi_jaccard = Jaccard::getInstance();
    double jaccard_actual;
    double jaccard_maximo = 0;
    int cluster;
    int i = 0;
    char ruta[200];
    *ruta = 0;
    char letra = 'a';
    while(!feof(centroides)){
        letra = fgetc(centroides);
        if(letra == '\n'){
            hashset_centroide->Load(ruta);
            jaccard_actual = mi_jaccard->Similarity(hashset_archivo_nuevo,hashset_centroide);
            if(jaccard_actual > jaccard_maximo){
                jaccard_maximo = jaccard_actual;
                cluster = i;
            }
            i++;
            *ruta = 0;
        }
        else{
            ruta[strlen(ruta)+1]='\0';
            ruta[strlen(ruta)]=letra;
        }
    }
    fclose(centroides);
    hashset_archivo_nuevo->Destroy();
    hashset_centroide->Destroy();
    char ruta_cluster[200];
    strncpy(ruta_cluster,PREFIJO_CLUSTER,strlen(PREFIJO_CLUSTER));
    stringstream stream;
    stream << cluster;
    string scluster = stream.str();
    strncpy(ruta_cluster+strlen(PREFIJO_CLUSTER),scluster.c_str(),strlen(scluster.c_str()));
    ruta_cluster[strlen(PREFIJO_CLUSTER)+strlen(scluster.c_str())]='\0';
    strncpy(ruta_cluster+strlen(ruta_cluster),".txt",strlen(".txt"));
    ruta_cluster[strlen(PREFIJO_CLUSTER)+strlen(scluster.c_str())+4]='\0';
    FILE* archivo_cluster = fopen(ruta_cluster,"a");
    FILE* listado = fopen(ARCH_LISTADO,"a");
    fprintf((FILE*)archivo_cluster,"%s\n",nombre_libro);
    fprintf((FILE*)listado,"%s   %s\n",nombre_libro,scluster.c_str());
    fclose(archivo_cluster);
    fclose(listado);
    return;
}

void testLog(){
    Log* lg = Log::getInstance();
    lg->ERROR("Prueba Error");
}

void testHashMin(){
        HashMin* hm = new HashMin();
        int e = hm->Execute();
        hm->Save("/home/fliaali/Descargas/Test/HashMin.txt");
}

void testDirectory(){
    string str = "/home/fliaali/Descargas/Test";
    string ext = ".h";
    std::vector<std::string> files;
    Directory::GetListPath(str, files, ext);
    bool e1=Directory::Existe(str);
    bool r1=Directory::Existe(ext);
    Directory::Remover(str); 
   
    string stt = "/home/fliaali/Descargas/Test/Test1/";
    Directory::Create(stt);
}

void testCluster(){
   int **tabla, i,row=20,col=2;
    tabla = new int*[row];
    for(i = 0; i < row; i++) 
      tabla[i] = new int[col];
    tabla[0][0] = 65;
    tabla[0][1] = 220;
    tabla[1][0] = 73;
    tabla[1][1] = 160;
    tabla[2][0] = 59;
    tabla[2][1] = 110;
    
    tabla[3][0] = 61;
    tabla[3][1] = 120;
    tabla[4][0] = 75;
    tabla[4][1] = 150;
    tabla[5][0] = 67;
    tabla[5][1] = 240;
    
    tabla[6][0] = 68;
    tabla[6][1] = 230;
    tabla[7][0] = 70;
    tabla[7][1] = 220;
    tabla[8][0] = 62;
    tabla[8][1] = 130;
    tabla[9][0] = 66;
    tabla[9][1] = 210;
    
    tabla[10][0] = 77;
    tabla[10][1] = 190;
    tabla[11][0] = 75;
    tabla[11][1] = 180;
    tabla[12][0] = 74;
    tabla[12][1] = 170;
    
    tabla[13][0] = 70;
    tabla[13][1] = 210;
    tabla[14][0] = 61;
    tabla[14][1] = 110;
    tabla[15][0] = 58;
    tabla[15][1] = 100;
    
    tabla[16][0] = 66;
    tabla[16][1] = 230;
    tabla[17][0] = 59;
    tabla[17][1] = 120;
    tabla[18][0] = 68;
    tabla[18][1] = 210;
    tabla[19][0] = 61;
    tabla[19][1] = 130;
    
    vector<string> files;
    string str = RUTA_HASHMINS_LEER;
    Directory::GetListPath(str, files, EXTENSION);
    ClusteringKMeans clustr(files, 3, files.size(), DEF_NUM_MINHASH, 30);
    int **cl = clustr.Cluster(false);
    clustr.SaveFiles(cl,RUTA_CLUSTER_CREAR,PREFIJO_CLUSTER,ARCH_CENTROIDES,ARCH_LISTADO);
    
  for (int k = 0; k < 3; ++k) // cada cluster
  {
       cout << "CLUSTER" << k <<  " ";
         
    cout << "\n";
    for (int i = 0; i < files.size(); ++i) {// cada tupla
      if (cl[i][0] == k)
      {
          cout << files[i] <<  " ";
          cout << "\n";
        //for (int j = 0; j < col; ++j)
        //  cout << tabla[i][j] <<  " ";
        //cout << "\n";
      }
    }
    cout << "\n";
  } 
}

void Prueba_Parser(){
    Parser* mi_parser = new Parser();
    mi_parser->Obtener_Vector_HashMin("Arch.txt","pepe.txt");
    int i = 0;
    FILE* veo_chars = fopen("pepe.txt","r");
    while(feof(veo_chars)==0){
        char letra = fgetc(veo_chars);
        i++;
    }
    printf("%d",i);
    fclose(veo_chars);
    mi_parser->Destruir();
}

void Prueba_Hash_Shingle(){
    Hashs* mi_hash = new Hashs();
    char* hash = mi_hash->F_Hashing_Shingle("onking");
    char* result =(char*)malloc(sizeof(char)*4);
    int c1 =115;
    int c2 = 84;
    int c3 = 134;
    int c4 = 152;
    strcat(result,(char*)&c1);
    strcat(result,(char*)&c2);
    strcat(result,(char*)&c3);
    strcat(result,(char*)&c4);
    
    if(strcmp(result,hash)==0) printf("Oh Yeah!");
}

void TestFClustering(){
    string str = "/home/fliaali/Descargas/Test";
    std::vector<std::string> files;
    Directory::GetListPath(str, files, EXTENSION);
    if (files.empty()) printf("No se encontraron archivos en el directorio");
    else{
        string stt = "/home/fliaali/Repositorio Datos/svn/Src/TpDatos/HashMins/";
        if(Directory::Existe(stt)) Directory::Remover(stt);
        Directory::Create(stt);
        int pos,k,largo;
        char* nombre;
        Parser* mi_parser = new Parser();
        int archivos_total = files.size();
        for(int i=0;i<archivos_total;i++){
                const char* archivo = files[i].c_str();
                //Generar Archivo Docs (Iddoc=i; Cat(0);Name:files(i)))
                pos = 0;
                for(k = 0;k<strlen(archivo);k++){
                    if(archivo[k]=='/') pos = k+1;
                }
                *nombre = 0;
                strcpy(nombre,"HashMins/hashmin_");
                largo = strlen(archivo);                 
                strncpy(nombre+17,archivo+pos,largo-pos);
                mi_parser->Obtener_Vector_HashMin(archivo,nombre);             
        }
        mi_parser->Destruir();
    }
    return;
}
void ToString(int i,int largo,char* salida){
    int ind = largo -1;
    while(i>0){
        salida[ind] = (char)(i%10+48);
        i/=10;
        ind --;
    }
    while(ind>=0){
        salida[ind]='0';
        ind--;
    }
}

void TestConvert(){
    int i = 55;
    char str[MAX_COMANDO];
    printf("%d",strlen(str));
    ToString(i,4,str);
    printf("%s",str);
}

void testHashSet(){
    //HashSet 0
    HashSet* hs0 = new HashSet();
    hs0->Load("/home/fliaali/Repositorio Datos/svn/Src/TpDatos/HashMins/hashmin_aerosmith-helter skelter.txt");
    int a = hs0->GetElem(0);
    int b = hs0->GetElem(1);
    
    //HashSet 1
    HashSet* hs1 = new HashSet();
    hs1->Load(hs0->GetVector());
    int a1 = hs1->GetElem(0);
    int b1 = hs1->GetElem(1);
    
    //HashSet 2
    HashSet* hs2 = new HashSet();
    hs2->Load("/home/fliaali/Repositorio Datos/svn/Src/TpDatos/HashMins/hashmin_daft punk - give life back to music.txt");
    
    //Jaccard
    Jaccard* j = Jaccard::getInstance();
    double similitud1 = j->Similarity(hs0, hs1);      // 1
    double similitud2 = j->Similarity(hs0, hs2);       
        
    hs0->Destroy();
    hs1->Destroy();
    hs2->Destroy();
    
    int s = 5;
}


int main(int argc, char** argv) {
    //testHashSet();
    //testHashMin(); 
    //Prueba_Parser();
    //testCluster();
    //Prueba_Hash_Shingle();
    //TestFClustering();
    //TestConvert();
    //testDirectory();
    //f_listar_grupos(2,argv);
    //char** a;
    //f_agregar_libro(3,a);
        
    char* comandos[] = {"-d", "-l", "-g", "-a"};
    t_opcion opcion;
    opcion = veo_comando_general(argc,argv,comandos);
    switch(opcion){
        case CLUSTERING: {
            f_clustering(argc,argv);
            break;
        }
        case LISTAR_LIBROS: {
            f_listar_libros(argc,argv);
            break;
        }
        case LISTAR_GRUPOS: {
            f_listar_grupos(argc,argv);
            break;
        }
        case AGREGAR_LIBRO: {
            f_agregar_libro(argc,argv);
            break;
        }
        default: printf("Comando Invalido\n");
                        
    }

    return 0;
}


